/*******************************************************************************
 * Copyright (c) 2011, 2012 Mia-Software.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Herve ESTEGUET (Mia-Software) - Bug 381352 - [Releng] There must be a project to configure the build by tycho
 *******************************************************************************/
package org.eclipse.releng.tycho.util;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.jar.JarFile;
import java.util.jar.Pack200;
import java.util.jar.Pack200.Packer;
import java.util.zip.GZIPOutputStream;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;

@SuppressWarnings("rawtypes")
public class Pack200Task extends Task {

	private File jar;
	private int level = 9;
	private boolean keepOrder = true;
	
	
	@SuppressWarnings("unchecked")
	@Override
	public void execute() throws BuildException {
		checkParams();

		Packer packer = Pack200.newPacker();

		// Initialize the state by setting the desired properties
		Map p = packer.properties();
		// take more time choosing codings for better compression
		p.put(Packer.EFFORT, String.valueOf(level));  // default is "5"
		// reorder files for better compression.
		p.put(Packer.KEEP_FILE_ORDER, keepOrder ? Packer.TRUE : Packer.FALSE);
		// smear modification times to a single value.
		p.put(Packer.MODIFICATION_TIME, Packer.KEEP);
		// transmitting a single request to use "store" mode.
		p.put(Packer.DEFLATE_HINT, Packer.FALSE);
		// throw an error if an attribute is unrecognized
		p.put(Packer.UNKNOWN_ATTRIBUTE, Packer.ERROR);
		
		try {
			packJar(packer, jar);
		} catch (IOException e) {
			throw new BuildException(String.format("An error occured while packing %s", jar), e, getLocation());
		}
	}

	public void setJar(final File jar) {
		this.jar = jar;
	}

	public void setLevel(final int level) {
		this.level = level;
	}

	public void setKeepOrder(final boolean keepOrder) {
		this.keepOrder = keepOrder;
	}

	private void checkParams() {
		if (jar == null || !jar.isFile()) {
			throw new BuildException("Missing jar attributes", getLocation());
		}
		if (level<1 || level>9) {
			throw new BuildException("The compression level should be an integer between 1 and 9");
		}
	}
	
	public static void main(final String[] args) throws Exception {
		Pack200Task packer = new Pack200Task();
		packer.setJar(new File(args[0]));
		packer.execute();
	}
	
	private File packJar(final Packer packer, final File jar) throws IOException {
		String jarPath = jar.getAbsolutePath();
		File output = new File(jarPath + ".pack.gz");
		log("Packing " + output);
		JarFile jarFile = new JarFile(jarPath);
		OutputStream fos = new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream(output)));
		// Call the packer
		packer.pack(jarFile, fos);
		jarFile.close();
		fos.close();
		return output;
	}
	
}
